﻿using System;
using System.Drawing;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using System.IO;
using SVM;
using ComputerVision.ANN;

namespace ComputerVision.Common
{
    public class ImageProcess
    {
        Model modelNum;
        Model modelCharNum;
        HaarCascade haarbienso;
        HaarCascade haarkytu;
        string strmucxam;
        double dblmucxam;

        public ImageProcess()
        {
            modelNum = Model.Read("svmNum.model");
            modelCharNum = Model.Read("svmCharNum.model");
            try
            {
                haarbienso = new HaarCascade(Application.StartupPath + "\\bienso.xml");
            }
            catch (Exception ex)
            {
                
            }

            try
            {
                haarkytu = new HaarCascade(Application.StartupPath + "\\kytu.xml");
            }
            catch (Exception ex)
            {
                throw;
            }
            
        }
        
        public Image<Bgr, byte> dinhviBienSo(Image<Bgr, byte> img)
        {
            //định vị biển số
            var grayImg = img.Convert<Gray, byte>();
            Image<Bgr, byte> result;
            var bs = grayImg.DetectHaarCascade(haarbienso)[0];
            foreach (var bs1 in bs)
            {
                result = img.Copy(bs1.rect).Resize(Convert.ToInt32(bs1.rect.Width * 360 / bs1.rect.Height), 360, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                return result;
            }
            return null;
        }
        public string NDkytu(string temp, Model model)
        {
            //sử dụng SVM để nhận dạng ký tự
            string kytu;
            var swrite = new StreamWriter("test.test");

            swrite.Write("0 " + temp);
            swrite.Close();

            var test = Problem.Read("test.test");
            Prediction.Predict(test, "result.out", model, false);

            var sread = new StreamReader("result.out");
            kytu = sread.ReadToEnd();
            sread.Close();
            return kytu.Trim();
        }
        public string NhanDienKyTu(Image<Bgr, byte> img, NeuralNetwork<string> a)
        {
            //giai đoạn nhận diện ký tự gồm 3 bước:
            //Bước 1: sắp xếp các ký tự từ trái qua phải
            //Bước 2: chuyển ảnh ký tự thành tập dữ liệu SVM hợp lệ
            //Bước 3: nhận diện các tập dữ liệu và nối thành chuỗi kết quả
            var grayImage = img.Convert<Gray, byte>();
            var kytu = grayImage.DetectHaarCascade(haarkytu)[0];
            //ảnh các ký tự
            var imgkytu = new Image<Gray, Byte>[10];
            Image<Gray, Byte> Part1 = null;
            Image<Gray, Byte> Part2 = null;
            Image<Gray, Byte> Part3 = null;
            Image<Gray, Byte> Part4 = null;
            int p1 = 0;
            //lưu các toạ độ của khung chữ nhật chứa ký tự
            var toado = new int[10];
            //sắp xếp các ký tự từ trái qua phải, từ trên xuống dưới
            foreach (var det in kytu)
            {
                if (det.rect.Y < 65 || det.rect.Y > 165)
                {
                    if (det.rect.Y > 170)
                    {
                        imgkytu[p1] = grayImage.Copy(det.rect).Resize(20, 48, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        toado[p1] = det.rect.X;
                        for (int k = 0; k <= p1 - 1; k++)
                        {
                            if (toado[p1] < toado[k])
                            {
                                var tempImage = imgkytu[p1];
                                imgkytu[p1] = imgkytu[k];
                                imgkytu[k] = tempImage;
                                int temp = toado[p1];
                                toado[p1] = toado[k];
                                toado[k] = temp;
                            }
                        }
                        p1 += 1;
                    }
                    else
                    {
                        if (det.rect.X > 50 && det.rect.X < 100)
                        {
                            Part1 = grayImage.Copy(det.rect).Resize(20, 48, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                        else if (det.rect.X > 100 && det.rect.X < grayImage.Width / 2)
                        {
                            Part2 = grayImage.Copy(det.rect).Resize(20, 48, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                        else if (det.rect.X > grayImage.Width / 2 && det.rect.X < 300)
                        {
                            Part3 = grayImage.Copy(det.rect).Resize(50, 50, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                        else
                        {
                            Part4 = grayImage.Copy(det.rect).Resize(20, 48, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                    }
                }
            }
            string temp1 = "";
            string temp2 = "";
            string temp4 = "";
            var temp5 = new string[10];
            //chuyển thành tập SVM hợp lệ
            if (imgkytu != null)
            {
                for (var i = 0; i <= p1 - 1; i++)
                {
                    imgkytu[i]._Not();
                    strmucxam = imgkytu[i].GetAverage().ToString();
                    dblmucxam = Convert.ToDouble(strmucxam.Substring(1, strmucxam.Length - 2));
                    for (int m = 0; m <= 47; m++)
                    {
                        for (int n = 0; n <= 19; n++)
                        {
                            if (imgkytu[i][m, n].Intensity > dblmucxam)
                            {
                                temp5[i] += (m * imgkytu[i].Width + n + 1) + ":1 ";
                            }
                        }
                    }
                }
            }

            if (Part1 != null)
            {
                Part1._Not();
                strmucxam = Part1.GetAverage().ToString();
                dblmucxam = Convert.ToDouble(strmucxam.Substring(1, strmucxam.Length - 2));
                for (var m = 0; m <= 47; m++)
                {
                    for (var n = 0; n <= 19; n++)
                    {
                        if (Part1[m, n].Intensity > dblmucxam)
                        {
                            temp1 += (m * Part1.Width + n + 1) + ":1 ";
                        }
                    }
                }
            }

            if (Part2 != null)
            {
                Part2._Not();
                strmucxam = Part2.GetAverage().ToString();
                dblmucxam = Convert.ToDouble(strmucxam.Substring(1, strmucxam.Length - 2));
                for (int m = 0; m <= 47; m++)
                {
                    for (int n = 0; n <= 19; n++)
                    {
                        if (Part2[m, n].Intensity > dblmucxam)
                        {
                            temp2 += (m * Part2.Width + n + 1) + ":1 ";
                        }
                    }
                }
            }


            if (Part3 != null)
            {
                //Part3._Not();
                //strmucxam = Part3.GetAverage().ToString();
                //dblmucxam = Convert.ToDouble(strmucxam.Substring(1, strmucxam.Length - 2));
                //for (int m = 0; m <= 47; m++)
                //{
                //    for (int n = 0; n <= 19; n++)
                //    {
                //        if (Part3[m, n].Intensity > dblmucxam)
                //        {
                //            temp3 += (m * Part3.Width + n + 1) + ":1 ";
                //        }
                //    }
                //}
            }

            if (Part4 != null)
            {
                Part4._Not();
                strmucxam = Part4.GetAverage().ToString();
                dblmucxam = Convert.ToDouble(strmucxam.Substring(1, strmucxam.Length - 2));
                for (var m = 0; m <= 47; m++)
                {
                    for (var n = 0; n <= 19; n++)
                    {
                        if (Part4[m, n].Intensity > dblmucxam)
                        {
                            temp4 += (m * Part4.Width + n + 1) + ":1 ";
                        }
                    }
                }
            }

            var result = "";
            if (Part1 != null)
            {
                result += NDkytu(temp1, modelNum);
            }
            else
            {
                result += "_";
            }
            if (Part2 != null)
            {
                result += NDkytu(temp2, modelNum);
            }
            else
            {
                result += "_";
            }
            result += "-";
            if (Part3 != null)
            {
               // result += ChuyenSo(NDkytu(temp3, modelCharNum));
                Part3 = Part3.ThresholdBinary(new Gray(150), new Gray(255));
                Part3.SmoothMedian(3);
                double[] input = ImageProcessing.ToMatrix(Part3.Bitmap, Part3.Height, Part3.Width);
                string MatchedHigh = "?", MatchedLow = "?";
                double OutputValueHight = 0, OutputValueLow = 0;
                a.Recognize(input, ref MatchedHigh, ref OutputValueHight,
                              ref MatchedLow, ref OutputValueLow);
                result += MatchedHigh[0];
            }
            else
            {
                result += "_";
            }
            if (Part4 != null)
            {
                result += ChuyenSo(NDkytu(temp4, modelCharNum));
            }
            else
            {
                result += "_";
            }
            result += "-";
            for (int j = 0; j <= p1 - 1; j++)
            {
                result += NDkytu(temp5[j], modelNum);
            }

            return result.Trim();
        }
        public string ChuyenSo(string s)
        {
            //chuyển các nhãn được SVM nhận dạng thành ký tự
            int i;
            int.TryParse(s, out i);
            string result;
            switch (i)
            {
                case 10:
                    result = "A";
                    break; // TODO: might not be correct. Was : Exit Select

                case 11:
                    result = "B";
                    break; // TODO: might not be correct. Was : Exit Select

                case 12:
                    result = "C";
                    break; // TODO: might not be correct. Was : Exit Select

                case 13:
                    result = "D";
                    break; // TODO: might not be correct. Was : Exit Select

                case 14:
                    result = "E";
                    break; // TODO: might not be correct. Was : Exit Select

                case 15:
                    result = "F";
                    break; // TODO: might not be correct. Was : Exit Select

                case 16:
                    result = "G";
                    break; // TODO: might not be correct. Was : Exit Select

                case 17:
                    result = "H";
                    break; // TODO: might not be correct. Was : Exit Select

                case 18:
                    result = "K";
                    break; // TODO: might not be correct. Was : Exit Select

                case 19:
                    result = "L";
                    break; // TODO: might not be correct. Was : Exit Select

                case 20:
                    result = "M";
                    break; // TODO: might not be correct. Was : Exit Select

                case 21:
                    result = "N";
                    break; // TODO: might not be correct. Was : Exit Select

                case 22:
                    result = "P";
                    break; // TODO: might not be correct. Was : Exit Select

                case 23:
                    result = "R";
                    break; // TODO: might not be correct. Was : Exit Select

                case 24:
                    result = "S";
                    break; // TODO: might not be correct. Was : Exit Select

                case 25:
                    result = "T";
                    break; // TODO: might not be correct. Was : Exit Select

                case 26:
                    result = "U";
                    break; // TODO: might not be correct. Was : Exit Select

                case 27:
                    result = "V";
                    break; // TODO: might not be correct. Was : Exit Select

                case 28:
                    result = "X";
                    break; // TODO: might not be correct. Was : Exit Select

                case 29:
                    result = "Y";
                    break; // TODO: might not be correct. Was : Exit Select

                case 30:
                    result = "Z";
                    break; // TODO: might not be correct. Was : Exit Select

                default:
                    result = i.ToString();
                    break; // TODO: might not be correct. Was : Exit Select
            }
            return result.Trim();
        }
        public string docbienso(Image<Bgr, byte> img, PictureBox picbox, NeuralNetwork<string> neuralNetwork)
        {
            //hàm trả về ký tự biển số và hiển thị ảnh biển số lên imgbox
            string bienso = "";
            var img2 = dinhviBienSo(img);
            if (img2 != null)
            {
                bienso = NhanDienKyTu(img2, neuralNetwork);
                picbox.Image = img2.ToBitmap();
            }
            return bienso;
        }

        public static Bitmap ConvertBytesToImg(byte[] bytes)
        {
            var mstream = new MemoryStream(bytes, 0, bytes.Length);
            mstream.Write(bytes, 0, bytes.Length);
            var newBitmap = new Bitmap(mstream);
            mstream.Flush();
            mstream.Dispose();
            return newBitmap;
        }

        public static byte[] ConvertToByteArray(Bitmap bit)
        {
            var converter = new ImageConverter();
            return (byte[])converter.ConvertTo(bit, typeof(byte[]));
        }

        public static byte[] ConvertToByteArray(Image bit)
        {
            var converter = new ImageConverter();
            return (byte[])converter.ConvertTo(bit, typeof(byte[]));
        }
    }
}
